home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 42
/
Amiga Format AFCD42 (Issue 126, Aug 1999).iso
/
-serious-
/
programming
/
other
/
gui4cli
/
ext
/
gcsound
/
src
/
gcsound.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-05-14
|
15KB
|
479 lines
/***********************************************************************
*
* GCSound 1.0 - D. Keletsekis (October 98)
*
* compile: SC GCSound NOSTACKCHECK LINK NOSTARTUP
* ..or have a look at the scoptions files..
*
* This is a "host" program for playing 8SVX sound samples.
* It can understand commands from ARexx or Gui4Cli and
* load & play many samples together, multitaskinglisingly..
*
* The name of the port opened is "gcsound" (note lower case)
*
* These are the current commands :
*
* QUIT - abort all sounds and quit
* LOAD <SampleFile> <Alias> (default speed/time/volume)
* PLAY <alias> <times/0> <volume> <speed/-1>
* SOUND <SampleFile> <times/0> <volume> <speed/-1> (load, play & quit)
* VOLUME <alias> <1-64>
* SPEED <alias> <?>
* TIMES <alias> <times/0>
* INFO <alias> (return "volume speed")
* UNLOAD <alias> (or "" for all samples - stop & unload)
* STOP <alias> (or "" for all samples - stop playing)
*
* From Gui4Cli they can be called either with :
* -> Call gcsound command arguments.. -or-
* -> SendRexx gcsound "command arguments" (note the quotes)
*
************************************************************************/
#define __USESYSBASE
#include <exec/exec.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <dos/dosextens.h>
#include <dos/rdargs.h>
#include <dos/dostags.h>
#include <devices/audio.h>
#include <graphics/gfxbase.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <dos.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/rexxsyslib.h>
#include <graphics/text.h>
#include <rexx/storage.h>
#include <datatypes/soundclass.h> // include soundclass
#include "Gui4Cli.h" // include Gui4Cli.h (for the message structure)
#include "gcsound_protos.h"
static const char VERSION[] = "\0$VER: gcsound 1.0 (D.Keletsekis Oct.98)";
#define BUFFER_SIZE 65536 // the buffer size (should be a tooltype)
#define CLEANMEM (MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC)
// We use this "treat a 4 character string as if it were a LONG
// integer" ID method for identifying our commands also.
// This means that *only* the first four letters of each command
// are checked - but it allows us to use a fast case statement.
#define MakeID(a,b,c,d) ((LONG)(a)<<24L | (LONG)(b)<<16L | (c)<<8 | (d))
#define QUIT MakeID('Q','U','I','T')
#define LOAD MakeID('L','O','A','D')
#define PLAY MakeID('P','L','A','Y')
#define SOUND MakeID('S','O','U','N')
#define VOLUME MakeID('V','O','L','U')
#define SPEED MakeID('S','P','E','E')
#define TIMES MakeID('T','I','M','E')
#define INFO MakeID('I','N','F','O')
#define UNLOAD MakeID('U','N','L','O')
#define STOP MakeID('S','T','O','P')
// #define ID_FORM MakeID('F','O','R','M')
struct myhandle // each sample has one of these..
{
struct VoiceHeader vh; // the 8SVX header
LONG bodystart; // offset of body start into file
LONG bodylength; // total body length
ULONG speed; // playback speed
ULONG volume; // volume (default=64)
ULONG times; // times to play
ULONG played; // times already played
UBYTE *buff1, *buff2; // the buffer pointers
LONG buffsize; // buffer size
BPTR fp; // the file pointer (if file is open)
char path[256]; // full name & path of file
char alias[40]; // alias - the given name (upper case)
struct IOAudio io1, io2; // Pointers to Audio IO structures
BOOL out1, out2; // flags indicating msgs outstanding
ULONG remain; // remaining data length (large samples)
BOOL reload; // 1 = reload sample before replaying
BOOL killflag; // 1 = kill sample when all msgs replied
BOOL playonce; // 1 = SOUND - load/play/quit sample
struct base *bs; // pointer to base
struct myhandle *next;
};
struct base // somewhere to hold everything
{
struct myhandle *toph; // top of handles linked list
struct MsgPort *soundport; // our sound reply port
ULONG clock; // clock constant
UBYTE retbuff[80]; // return text..
LONG users; // how many guis are using us
struct DosLibrary *dosbase; // carry these around..
struct ExecBase *sysbase;
};
// ===============================================================
// MAIN() - note there is no need for a main() function
// The program starts at the 1st function it finds, which
// can be any name..
// ===============================================================
int main(void)
{
// these are the libraries we need
struct ExecBase *SysBase = (*((struct ExecBase **) 4));
struct DosLibrary *DOSBase=NULL;
struct Process *myself = (struct Process *)(SysBase->ThisTask);
struct MsgPort *myport=NULL; // our port
ULONG soundsig, portsig, sig; // port signal masks
struct g4cmsg *msg; // Gui4Cli message pointer
int rc = 10; // return code
BOOL endflag = 0; // control flags
BOOL errorflag = 0;
struct base *bs=NULL; // our base struct pointer
struct myhandle *h, *hh;
struct IOAudio *io;
struct Task *mt=NULL; // for bumping task priority
BYTE oldpri=0;
LONG readmore, ret;
LONG rxargs[6]; // for rexx msg parsing
struct RDArgs *rdargs;
struct RexxMsg *rxmsg;
struct RexxSysBase *RexxSysBase = NULL;
// -------------------- open the dos library or die..
if (!(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 36L)))
{ myself->pr_Result2 = ERROR_INVALID_RESIDENT_LIBRARY;
goto endprog;
}
// if rexx is not opened, rexx commands will not be executed
RexxSysBase = (struct RexxSysBase *)OpenLibrary ("rexxsyslib.library", 36L);
// -------------------- if gcsound is already running ++users & quit
if (myport = FindPort("gcsound"))
{ if (msg = (struct g4cmsg *)AllocVec(sizeof(struct g4cmsg), CLEANMEM))
{ msg->magic = 392002; // the only thing that's checked
msg->node.mn_Length = sizeof(struct g4cmsg);
PutMsg (myport, &msg->node);
// msg will not be replied & *will* be freeveced
}
myport = NULL; // so that it's not freed
rc = 0;
goto endprog;
}
// -------------------- get our main base structure
if (!(bs = (struct base *)AllocVec(sizeof(struct base), CLEANMEM)))
goto endprog;
bs->sysbase = SysBase;
bs->dosbase = DOSBase;
bs->users = 1; // the guy who loaded us is also our 1st user
if (!getconstant(bs)) goto endprog;
// --------------------- increase our priority - why ?
mt = FindTask(NULL);
oldpri = SetTaskPri(mt,21);
// --------------------- Open message ports or die..
bs->soundport = CreatePort(0,0); // sound return port
myport = openport ("gcsound", SysBase, DOSBase); // G4C port
if (!bs->soundport || !myport)
{ PutStr ("Couldn't open ports!\n");
goto endprog;
}
portsig = (1 << myport->mp_SigBit); // create signal masks
soundsig = (1 << bs->soundport->mp_SigBit);
// ---------------------- Main wait() & process loop
// quit on endflag but after all samples have quit first
while ((!endflag) || (bs->toph))
{
// wait on combined port signals
sig = Wait (portsig | soundsig);
// ------------------- messages from Gui4Cli, ARexx etc
// we support messages from an other instance of this program, or
// from Gui4Cli or from ARexx - we check to see what we got
if (sig & portsig)
{
while (msg = (struct g4cmsg *)GetMsg(myport))
{
// if it's from an other instance of gcsound, ++users
if (msg->magic == 392002)
{ ++bs->users;
FreeVec (msg); // do *not* reply - *do* FreeVec()
}
else if (msg->magic == 392001) // from gui4cli
{
// check that its like we expect it..
if ((msg->type == GM_COMMAND) && msg->gcmain && msg->com)
{
ret = docommand ((*((LONG *)msg->com)), bs, msg->args[0], msg->args[1], msg->args[2], msg->args[3]);
if (ret < 0) endflag = 1; // quit
else
{ // if there is a return, attach string
if (bs->retbuff[0])
{ if (msg->msgret = (UBYTE *)AllocVec(80, CLEANMEM))
strcpy (msg->msgret, bs->retbuff);
bs->retbuff[0] = '\0';
}
msg->res = ret;
}